#!/usr/bin/python3
# -*- coding: utf-8 -*-
# coding=utf-8
# Author: BillySir
from __future__ import print_function, annotations
from typing import *
from chess import *
from chess_board import Cell


class Rule(Cell):
    """所有规则的基类"""

    def __init__(self, basket: ChessBasket):
        super(Rule, self).__init__(basket)

    def __str__(self):
        return "rule[%d]:%s" % (self.index, self.chess)

    __repr__ = __str__

    @classmethod
    def batch_bind_parents(cls, rules: List[Rule], parents_list: List[List[Cell]]):
        if len(rules) != len(parents_list):
            raise Exception("len of rules not equals len of parents_list. len(rules):%d, len(parents_list):%d" % (
                len(rules), len(parents_list)))
        for i in range(len(rules)):
            rules[i].bind_parents(parents_list[i])


class RuleSum(Rule):
    """和的规则"""

    def __init__(self, expect_total, basket: ChessBasket):
        super(RuleSum, self).__init__(basket)
        self._expect_total = expect_total

    def validate(self):
        actual_total = 0
        none_cell_list: List[Cell] = []
        for cell in self.parents:
            if cell.chess is None:
                none_cell_list.append(cell)
                continue
            actual_total += cell.chess.value
        none_cell_count = len(none_cell_list)
        if none_cell_count > 0:
            # 有多个未填时，判断是否超出范围
            max_n = self._basket.get_sum_max_n(none_cell_count)
            min_n = self._basket.get_sum_min_n(none_cell_count)
            if min_n + actual_total <= self._expect_total <= max_n + actual_total:
                return True
            return False
        if actual_total != self._expect_total:
            return False
        self.set_chess(actual_total)
        return True

    def can_fill(self, chess_list, parent: Cell):
        """获取可下的棋子集合与给定的chess_list的交集"""
        if parent.chess is not None:
            raise Exception("parent.chess is not None:" + parent.chess)

        actual_total = 0
        none_cell_list: List[Cell] = []
        for cell in self.parents:
            if cell.chess is None:
                none_cell_list.append(cell)
                continue
            actual_total += cell.chess.value
        none_cell_count = len(none_cell_list)

        assert none_cell_count >= 1, "found no empty cell in rule:" + str(self)
        if none_cell_count == 1:
            chess_list1 = self._basket.get_chess_by_value(self._expect_total - actual_total)
            return list(set(chess_list) & set(chess_list1))

        # 有多个未填时，判断是否超出范围
        max_n_total = self._basket.get_sum_max_n(none_cell_count - 1)
        min_n_total = self._basket.get_sum_min_n(none_cell_count - 1)
        max_value = self._expect_total - actual_total - min_n_total
        min_value = self._expect_total - actual_total - max_n_total
        return [chess for chess in chess_list if min_value <= chess.value <= max_value]
